package com.lx.boot.web.convert.deserializer;

import com.fasterxml.jackson.annotation.JacksonAnnotationsInside;
import com.lx.annotation.Note;
import com.lx.boot.OS;
import com.lx.boot.web.convert.DFunction;
import com.lx.boot.web.convert.deserializer.DecryptDeserialize.DecryptDFunction;
import com.lx.util.LX;
import com.lx.util.secure.algorithm.SecureAlgorithm;
import com.lx.util.secure.algorithm.SecureType;
import com.lx.util.secure.algorithm.coder.CoderType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.lang.annotation.*;
import java.util.function.Function;

@Inherited
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD,ElementType.TYPE,ElementType.PARAMETER})
@Documented
@JacksonAnnotationsInside
@Deserialize(value = DecryptDeserialize.class,function = DecryptDFunction.class)
public @interface DecryptDeserialize {

    Logger log = LoggerFactory.getLogger(DecryptDeserialize.class);

    @Note("指定解码类型")
    SecureType value();

    @Note("当指定secureAlgorithm()时,优先执行该方法获取,并传入此参数. 否则判断readConfig()是否通过配置文件的key来获取密钥")
    String key();

    @Note("指定key是直接配置在注解上还是读取配置文件")
    boolean readConfig() default true;

    @Note("对key进行解码")
    CoderType keyCoder() default CoderType.NONE;

    @Note("加密完成后的编码格式")
    CoderType coderType() default CoderType.NONE;

    @Note("当字段类型为String时需要指定编码格式")
    CoderType returnCoder() default CoderType.NONE;

    @Note("自定义解密类,优先使用这个配置,参数为key()")
    public Class<? extends Function<String, SecureAlgorithm>>[] secureAlgorithm() default {};

    public static  class DecryptDFunction implements DFunction<DeserializerPara, DecryptDeserialize, Object> {
        @Override
        public Object apply(DeserializerPara deserializerPara, DecryptDeserialize convert) {
            Object value = deserializerPara.getValue();
            if (value == null){
                return null;
            }
            try {
                Class filedType = deserializerPara.getFiledType();
                if (String.class.isAssignableFrom(filedType)){
                    if (CoderType.NONE == convert.returnCoder()){
                        throw new RuntimeException("当解密为String时需要指定编码格式:returnCoder()");
                    }
                    return convert.returnCoder().encodeToString(getSecureAlgorithm(convert).decrypt((String) value));
                }else if (byte[].class.isAssignableFrom(filedType)){
                    return getSecureAlgorithm(convert).decrypt((byte[]) value);
                }
            }catch (Exception e){
                log.error("解密失败!请检查参数.",e);
                throw new RuntimeException(e);
            }

            throw new RuntimeException("请检查待解码/解密的参数类型是否为String 或 byte[]");
        }

        SecureAlgorithm getSecureAlgorithm(DecryptDeserialize convert){
            if (convert.secureAlgorithm().length>0L){
                try {
                    convert.secureAlgorithm()[0].newInstance().apply(convert.key());
                } catch (Exception e) {
                    throw new RuntimeException(e);
                }
            }
            LX.exObj(convert.key(),"请在注解上配置key");
            String keyStr;
            if (convert.readConfig()){
                keyStr = OS.getProperty(convert.key());
                LX.exObj(keyStr, "请检查配置文件中是否配置"+convert.key());
            }else{
                keyStr = convert.key();
            }
            SecureAlgorithm secureAlgorithm;
            if (convert.keyCoder() == CoderType.NONE){
                secureAlgorithm = convert.value().getSecureAlgorithm(keyStr);
            }else{
                byte[] decode = convert.keyCoder().decode(keyStr);
                secureAlgorithm = convert.value().getSecureAlgorithm(decode);
            }
            if (convert.coderType() != CoderType.NONE){
                secureAlgorithm.coderType(convert.coderType());
            }
            return secureAlgorithm;
        }
    }

}
